//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file compiler.h
  * @brief The compiler
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGUTTARUIS__COMPILER__H_
#define __SAGUTTARUIS__COMPILER__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/parser/pAST.h"
#include "sagittarius/symtab/symtab.h"
#include "sagittarius/builtins/builtins.h"
#include "sagittarius/builtins/builtinfun.h"
#include "sagittarius/session/session.h"
#include <stdarg.h>

#ifdef __cplusplus
extern "C" {
#endif

#if 0
typedef struct __compiledFun compiledFun;

/** @brief Local info
 */
typedef struct {
    /// Is the local allocated on the heap?
    int onheap;
    /// True if type does not change (in this block)
    int isstatic;
    /// The symbol (not needed when we have name object)
    symcode s;
    /// name object
    sg_name_val* nm;
    /// is function?
    //int isfun;
    //compiledFun* cf;
    //sg_type* 
} localinfo;

localinfo* create_li();

void release_li(localinfo* t);

/** @brief Scope
 */
typedef struct {
    /// num
    uint64 n;
    /// cap
    uint64 c;
    /// buf
    localinfo** l;
} cscope;

/// Init scope
cscope* create_scope();

/// Delete scope
void release_scope(cscope* z);

/** @brief Scope contains symbol?
 */
int sym_in_scope(cscope* z, symcode s);

/** @brief Get local
 */
localinfo* scope_get_local(cscope* z, symcode s);

/** @brief Scope push; does not add if already exists
 */
void scope_insert_sym(cscope* z, symcode s);

/** @brief dump
 */
void dump_scope(int fd, cscope* z, symtab* st, uint64 ind);

#endif

typedef enum {
    ST_INVALID,
    ST_BUILTIN_TYPE,
    ST_BUILTIN_VAL,
    //ST_BUILTIN_FUN,
    ST_LOCAL
} SYMTYPE;

/** @brief Compiled node
 */
typedef struct __compiledNode {
    /// Original AST node
    parserExp* p;
    
    struct __compiledNode* a;
    struct __compiledNode* b;
    
    parserExpType ptype;
    
    uint64 nargs;
    
    symcode s;
    
    SYMTYPE st;
    
    sg_value* val;
    
    /// local scope
    sg_fctx_val* z;
    
    /*union {
        sg_name_val* li;
        /// Builtin reference
        sg_type* bi;
    } scp;*/
} compiledNode;

/** @brief Create
 */
compiledNode* create_compiled_node(parserExp* p);

/** @brief Release
 */
void releaseCompiledNode(compiledNode* x);

void dumpCompiledNode(int fd, compiledNode* x, uint64 ind, symtab* st, sg_OpPrec prec);

/** @brief Compiled function
 */
typedef struct __compiledFun {
    /// Original AST node
    functionDef* p;
    /// Symbol
    symcode s;
    /// # args
    uint64 nt;
    sg_fun_val* fv;
    sg_fctx_val* ctx;
    sg_name_val* m;
    /// Body
    compiledNode* b;
} compiledFun;

#if 0
/** @brief Create
 * @details Expects a -1 terminated list of @ref typecode referring to parameter types
 */
compiledFun* createCompiledFun(functionDef* p, typecode t, ...);

/** @brief Create
 * @details Expects a -1 terminated list of @ref typecode referring to parameter types
 */
compiledFun* vcreateCompiledFun(functionDef* p, typecode t, va_list v);
#endif

/** @brief Release
 */
void releaseCompiledFun(compiledFun* f);

/** @brief Compiled source
 */
typedef struct __compiledSrc {
    /// Global scope
    sg_fctx_val* g;
    /// Number of function definitions
    size_t nf;
    /// Function definitions
    compiledFun** f;
    /// Number of nodes
    //uint64 n;
    /// Body
    compiledNode* x;
    /// Original AST node
    sourceFrag* p;
    /// Optional sym table
    symtab* st;
} compiledSrc;

/** @brief Make a compiler from the AST
 */
compiledSrc* constructCompiler(sourceFrag* s);

/** @brief Release
 */
void releaseCompiler(compiledSrc* c);

/** @brief Get fun def
 */
functionDef* srcResolveSrcFun(compiledSrc* c, symcode s);

/** @brief Dumps info about the compiler
 */
void dumpCompiler(int fd, compiledSrc* c, uint64 ind, symtab* st);

/** @brief Do the first pass
 */
int compileFirstPass(compiledSrc* s);

/** @brief Emit error message
 */
void compilerErr(compiledSrc* c, const char* str, ...);
void vcompilerErr(compiledSrc* c, const char* str, va_list v);
void compilerMsg(compiledSrc* c, const char* str, ...);
void vcompilerMsg(compiledSrc* c, const char* str, va_list v);

/** @brief Validate
 */
int validateNodePass1(compiledSrc* c, sg_fctx_val* z, compiledNode* x);

compiledFun* srcResolveFun(compiledSrc* c, sg_fctx_val* z, symcode s);

/** @brief Compile options
 */
typedef struct {
    /// Instantiate all symbols
    //int ins_all_syms;
    /// Pass number for networks
    int net_pass;
} compileOpt;

compileOpt defaultCompOpt();

/** @brief Compile
 */
int compileNode(compiledSrc* c, sg_fctx_val* z, compiledNode* x, compileOpt opt);

#ifdef __cplusplus
}//extern "C"
#endif

#endif
